<template>
  <div v-if="computeIsShow" style="display: inline-block;margin-right: 10px;margin-bottom: 5px">
    <el-button v-bind="{...computeButtonProps}" @click="handleClick">{{computeLabel}}</el-button>
    <el-dialog v-if="visible" :title="_formOption.title" v-bind="{...dialogProps}" v-model="visible" append-to-body>
      <el-form ref="rowForm" :model="formData" :rules="_formOption.rules" label-width="150px">
        <component v-if="_formOption.component" :is="_formOption.component" v-model="formData" v-model:visible="visible"
                   v-bind="{ formOption: _formOption, rowForm, action, execute, selection, row, _table }" v-model:params="params"
                   @search="emit('search')" ref="formContent"
        />
        <template v-else>
          <common-element v-for="option in _formOption.options" v-bind="option" v-model="formData[option.prop]" :action="action"
                          @change="val=>option.onChange && option.onChange(val, formData, _table)"
                          @input="val=>option.onInput && option.onInput(val, formData, _table)"
          />
        </template>
      </el-form>
      <template #footer v-if="!hideButton && !_formOption.hideButton">
        <div class="dialog-footer">
          <common-button v-if="buttonConfirm.isShow" v-bind="buttonConfirm" @click="execute" type="primary"/>
          <common-button v-if="buttonCancel.isShow" v-bind="buttonCancel" @click="visible = false"/>
        </div>
      </template>
    </el-dialog>
  </div>
</template>

<script setup>
import {commonQuery} from "./api/index.js";
import {ElButton, ElDialog, ElForm, ElMessage, ElMessageBox} from "element-plus";
import CommonButton from "./CommonButton.vue";
import {ref, computed, defineEmits, defineModel, defineProps} from "vue";
import CommonElement from "./CommonElement.vue";
import CommonImport from "./form/CommonImport.vue";
const rowForm = ref()
const formContent = ref()
const props = defineProps({
  _table: Object,
  selection: Array,
  row: Object,
  label: String,
  //'delete' | 'add' | 'edit' | 'detail'
  //内置的按钮,以location属性区分顶部和行内按钮，此项有值时，显示内置按钮
  action: String,
  //'top' | 'row'
  location: {
    type: String,
    default: 'row'
  },
  _before: Function,
  _execute: Function,
  /*
  {
    //语法与content一致
    //这里只是普通字符串，但支持${}里面写js，能调用的参数为form, selection, row, table
    title: '删除操作确认',
    //这里只是普通字符串，但支持${}里面写js，能调用的参数为form, selection, row, table
    content: '确认删除这${(selection && selection.length) || 0}个${table.simpleTitle}？',
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning',
  }
   */
  confirm: Object,
  _after: Function,
  //(formData, selection, row, _table) => true
  isShow: {
    type: [Function, Boolean],
    default: true
  },
  _beforeDialog: Function,
  //将props传到按钮组件上（el-button）
  buttonProps: Object,
  //将props传到弹窗组件上（el-dialog）
  dialogProps: Object,
  //表单页面配置,如果此处配置了formOption,表示确认打开配置的表单后，才会执行_before, _execute, _after
  formOption: Object,
  emptyData: Object,
  formatData: Function,
  ak: String,
  excelOption: {
    type: Object,
    default: () => ({columns: [], sheet: '', fileName: ''})
  },
  hideButton: {
    type: Boolean,
    default: false
  },
})
const params = ref({})
const {primaryKey, baseUrl} = props._table.$props
const {getById} = commonQuery(baseUrl)
const visible = defineModel('visible', { type: Boolean, default: false })
const formData = ref({})
const computeLabel = computed(() => {
  if (props.label) return props.label
  switch (props.action) {
    case 'delete':
      return '删除'
    case 'add':
      return '新增'
    case 'edit':
      return '编辑'
    case 'detail':
      return '详情'
    case 'importTemplate':
      return '下载导入模板'
    case 'importData':
      return '批量导入'
    default:
      return ''
  }
})
const computeIsShow = computed(() => {
  switch (typeof props.isShow) {
    case 'function':
      return props.isShow(props.selection, props.row, props._table, form)
    case 'boolean':
      return props.isShow
    default:
      return true
  }
})
const computeButtonProps = computed(() => {
  if (props.buttonProps) {
    return props.buttonProps
  } else {
    switch (props.action) {
      case 'delete':
        return {
          type: 'danger',
          icon: 'Delete'
        }
      case 'add':
        return {
          type: 'primary',
          icon: 'Plus'
        }
      case 'edit':
        return {
          type: 'primary',
          icon: 'Edit'
        }
      case 'detail':
        return {
          type: 'info',
          icon: 'InfoFilled'
        }
      default:
        return {
          type: 'default',
        }
    }
  }
})
const buttonConfirm = computed(() => {
  if (props.formOption && props.formOption.buttonConfirm && props.formOption.buttonConfirm.label) {
    return props.formOption.buttonConfirm
  } else {
    return {
      label: '确 定',
      className: '',
      isShow: true
    }
  }
})
const buttonCancel = computed(() => {
  if (props.formOption && props.formOption.buttonCancel && props.formOption.buttonCancel.label) {
    return props.formOption.buttonCancel
  } else {
    return {
      label: '取 消',
      className: '',
      isShow: true
    }
  }
})
const defaultOptions = computed(()=>{
  if (props.emptyData) {
    return Object.keys(props.emptyData).map(prop => ({
      prop,
      label: prop,
      props: {
        placeholder: '请输入' + prop,
      },
    }))
  } else {
    return []
  }
})
const _formOption = computed(() => {
  if (props.formOption && Object.keys(props.formOption).length) {
    return {
      ...props.formOption,
      options: props.formOption.options || [],
      hideButton: props.formOption.hideButton === undefined ? props.action === 'detail' : props.formOption.hideButton,
    }
  } else {
    switch (props.action) {
      case 'delete':
        return {
          isForm: false,
          isDefault: true,
        }
      case 'add':
        return {
          title: `新增${props._table.simpleTitle}`,
          isDefault: true,
          options: defaultOptions.value,
        }
      case 'edit':
        return {
          title: `编辑${props._table.simpleTitle}`,
          isDefault: true,
          options: defaultOptions.value,
        }
      case 'detail':
        return {
          title: `${props._table.simpleTitle}明细`,
          isDefault: true,
          options: defaultOptions.value,
          hideButton: true,
        }
      case 'importTemplate':
        return {
          isForm: false,
          title: `下载导入模板`,
          isDefault: true,
        }
      case 'importData':
        return {
          component: CommonImport,
          title: `批量导入`,
          isDefault: true,
        }
      default:
        return {
          isForm: false,
          isDefault: false,
        }
    }
  }
})
const emit = defineEmits(['add', 'edit', 'delete', 'search', 'importTemplate', 'importData'])
async function handleClick() {
  if (_formOption.value.isForm !== false) {
    const selection = JSON.parse(JSON.stringify(props.selection || []))
    let row = JSON.parse(JSON.stringify(props.row || {}))
    if (row && row[primaryKey]) {
      const {success, msg, data} = await getById(props.row[primaryKey])
      if (success) {
        row = data
      } else {
        ElMessage.error(msg)
      }
    }
    const emptyData = JSON.parse(JSON.stringify(props.emptyData || {}))
    if (props.action === 'add') {
      formData.value = emptyData
    } else if (props.location === 'top') {
      formData.value = selection
    } else if (props.location === 'row'){
      formData.value = row
    } else {
      formData.value = {}
    }
    if (props.formatData) {
      await props.formatData(formData.value)
    }
    if (props._beforeDialog) {
      const beforeDialog = await props._beforeDialog(formData.value, selection, row, props._table)
      if (!beforeDialog) return
    }
    visible.value = true
  } else {
    await execute()
  }
}
async function execute() {
  const {_before, confirm, _execute, _after, selection, row, _table, action} = props
  const isForm = _formOption.value.isForm !== false
  if (isForm) {
    const result = await rowForm.value.validate()
    if (!result) return
  }
  if (formContent.value && formContent.value.submit !== undefined) {
    const submitResult = await formContent.value.submit()
    if (!submitResult) return
  }
  let _beforeResult, _confirmResult
  //执行前置函数
  if (_before) {
    _beforeResult = await _before(formData.value, selection, row, _table, params.value)
    if (!_beforeResult) return
  }
  //执行前置弹窗
  const title = confirm && confirm.title && confirm.title.replace(/\${(.*?)}/g, (match, p1) => {
    return eval(p1)
  }) || '提示信息'
  const content = confirm && confirm.content && confirm.content.replace(/\${(.*?)}/g, (match, p1) => {
    return eval(p1)
  }) || ''
  const confirmButtonText = confirm && confirm.confirmButtonText || '确定'
  const cancelButtonText = confirm && confirm.cancelButtonText || '取消'
  const isTop = props.location === 'top'
  if (confirm && confirm.title) {
    if (title && content) {
      _confirmResult = await ElMessageBox.confirm(content, title, {
        confirmButtonText,
        cancelButtonText,
        type: confirm.type || 'warning',
      })
      if (!_confirmResult) return
    }
  } else if (action === 'delete') {
    if (isTop) {
      if (!selection || !selection.length) {
        ElMessage.warning('请选择要删除的数据')
        return
      }
    }
    _confirmResult = await ElMessageBox.confirm(
        content || `确认删除这${isTop ? selection && selection.length : 1}个${_table.simpleTitle}？`,
        title || '删除操作确认', {
      confirmButtonText,
      cancelButtonText,
      type: 'warning',
    })
    if (!_confirmResult) return
  }
  //执行
  if (_execute) {
    await _execute(formData.value, selection, row, _table, params.value)
  }
  //内置执行
  const isDefault = !_execute && action
  if (!_execute && action) {
    switch (action) {
      case 'add':
        emit('add', formData.value, props.ak)
        break
      case 'edit':
        emit('edit', formData.value, props.ak)
        break
      case 'delete':
        const _selection = isTop ? selection : [row]
        emit('delete', _selection)
        break
      case 'importTemplate':
        emit('importTemplate', props.excelOption)
        break
      case 'importData':
        emit('importData', {...params.value, ...props.excelOption}, props.ak)
        break
      default:
        return
    }
  }
  if (_after) {
    await _after(formData.value, selection, row, _table, params.value)
  }
  if (isForm && !isDefault) {
    visible.value = false
  }
}
</script>

<style scoped lang="scss">

</style>
